package com.top.art.manager;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.top.art.bo.AllocationPageBO;
import com.top.art.bo.DistributeBO;
import com.top.art.bo.TeachersBO;
import com.top.art.converter.TeacherAllocationConverter;
import com.top.art.converter.UserInfoConverter;
import com.top.art.entity.*;
import com.top.art.enums.CourseEnum;
import com.top.art.enums.DistributeTypeEnum;
import com.top.art.exception.ArtException;
import com.top.art.service.*;
import com.top.art.tool.AuthTool;
import com.top.art.tool.Constant;
import com.top.art.vo.AllocationVO;
import com.top.art.vo.TeacherAllocationVO;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.Comparator;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * The type Teacher allocation manager.
 *
 * @author hjh
 * @version 2020 /10/6-10:05
 */
@Slf4j
@Component
public class TeacherAllocationManager {

    @Autowired
    private ITeacherAllocationService teacherAllocationService;

    @Resource
    private TeacherAllocationConverter teacherAllocationConverter;

    @Autowired
    private IUserInfoService userInfoService;

    @Resource
    private UserInfoConverter userInfoConverter;

    @Autowired
    private IUserCourseService userCourseService;

    @Autowired
    private IUserProvinceService userProvinceService;

    @Autowired
    private IExaminationPaperService examinationPaperService;

    @Autowired
    private IExamineeInfoService examineeInfoService;

    @Autowired
    private IExaminationInfoService examinationInfoService;

    @Autowired
    private IConstantsService constantsService;

    @Autowired
    private IAllocationProvinceService allocationProvinceService;

    /**
     * Page page.
     *
     * @param bo the bo
     * @return the page
     */
    public Page<AllocationVO> page(AllocationPageBO bo) {
        Page<AllocationVO> voPage = new Page<>(bo.getCurrent(), bo.getSize());
        if (StringUtils.isBlank(bo.getProvince())) {
            bo.setAllocationIds(allocationProvinceService.list(Wrappers.<AllocationProvince>lambdaQuery().eq(AllocationProvince::getProvince, bo.getProvince()))
                    .stream().map(AllocationProvince::getAllocationId).collect(Collectors.toList()));
        }
        IPage<TeacherAllocation> page = teacherAllocationService.page(bo);
        voPage.setTotal(page.getTotal());
        voPage.setRecords(page.getRecords().stream().map(x -> {
            AllocationVO vo = teacherAllocationConverter.do2vo(x);
            vo.setProvince(allocationProvinceService.list(Wrappers.<AllocationProvince>lambdaQuery()
                    .eq(AllocationProvince::getAllocationId, x.getId())).stream().map(AllocationProvince::getProvince).collect(Collectors.joining(",")));
            return vo;
        }).collect(Collectors.toList()));
        return voPage;
    }

    /**
     * Teachers list.
     *
     * @param bo the bo
     * @return the list
     */
    public TeacherAllocationVO teachers(TeachersBO bo) {
        TeacherAllocationVO vo = new TeacherAllocationVO();
        Set<String> accounts = userCourseService.list(Wrappers.<UserCourse>lambdaQuery().eq(UserCourse::getCourse, bo.getCourse()).select(UserCourse::getAccount))
                .stream().map(UserCourse::getAccount).collect(Collectors.toSet());
        accounts.addAll(userProvinceService.list(Wrappers.<UserProvince>lambdaQuery().in(UserProvince::getProvince, bo.getProvinces()).select(UserProvince::getAccount))
                .stream().map(UserProvince::getAccount).collect(Collectors.toList()));
        if (CollectionUtils.isEmpty(accounts)) {
            return vo;
        }
        vo.setTeachers(userInfoConverter.dos2userVOs(userInfoService.list(Wrappers.<UserInfo>lambdaQuery().eq(UserInfo::getRole, "阅卷老师")
                .in(CollectionUtils.isNotEmpty(accounts), UserInfo::getAccount, accounts))));
        vo.setDistributeType(Optional.ofNullable(constantsService.getOne(Wrappers.<Constants>lambdaQuery().eq(Constants::getLockKey, Constant.DISTRIBUTE_TYPE)))
                .orElse(new Constants()).getLockKey());
        return vo;
    }

    /**
     * Examination count int.
     *
     * @return the int
     */
    public int examinationCount() {
        return examinationInfoService.count(Wrappers.<ExaminationInfo>lambdaQuery().eq(ExaminationInfo::getActivityStatus, 1)
                .isNull(ExaminationInfo::getAccount));
    }

    /**
     * Paper count int.
     *
     * @return the int
     */
    public int paperCount() {
        return examinationPaperService.count(Wrappers.<ExaminationPaper>lambdaQuery().eq(ExaminationPaper::getEnable, 1)
                .isNull(ExaminationPaper::getAccount));
    }

    /**
     * Distribute boolean.
     *
     * @param bo the bo
     * @return the boolean
     */
    @Transactional(rollbackFor = Exception.class)
    public boolean distribute(DistributeBO bo) {
        String account = AuthTool.currentUser().getAccount();
        DistributeTypeEnum distributeTypeEnum = DistributeTypeEnum.getDistributeTypeEnum(bo.getDistributeType());
        if (distributeTypeEnum == null) {
            throw new ArtException(5004, "分配方式未找到");
        }
        Constants constants = constantsService.getOne(Wrappers.<Constants>lambdaQuery().eq(Constants::getLockKey, Constant.DISTRIBUTE_TYPE));
        if (constants != null && !StringUtils.equals(constants.getLockKey(), bo.getDistributeType())) {
            throw new ArtException(5004, "已有分配方式，传值不匹配");
        }
        int countVO = bo.getTeachers().stream().mapToInt(DistributeBO.TeacherAllocationBO::getCount).sum();
        //试卷分配
        bo.getTeachers().forEach(x -> {
            x.setProvinces(userProvinceService.list(Wrappers.<UserProvince>lambdaQuery().eq(UserProvince::getAccount, x.getAccount()))
                    .stream().map(UserProvince::getProvince).collect(Collectors.toList()));
        });
        //按照省份数量从小到大排序
        bo.getTeachers().sort(Comparator.comparing(x -> x.getProvinces().size(), Comparator.naturalOrder()));
        if (distributeTypeEnum == DistributeTypeEnum.PAPER) {
            if (countVO > paperCount()) {
                throw new ArtException(5004, "试卷分配总数配置超过总数");
            }
            for (DistributeBO.TeacherAllocationBO x : bo.getTeachers()) {
                List<String> admissionTicketCodes = examineeInfoService.list(Wrappers.<ExamineeInfo>lambdaQuery().select(ExamineeInfo::getAdmissionTicketCode)
                        .eq(ExamineeInfo::getProvince, x.getProvinces()).last("LIMIT " + x.getCount()))
                        .stream().map(ExamineeInfo::getAdmissionTicketCode).collect(Collectors.toList());
                if (CollectionUtils.isEmpty(admissionTicketCodes)) {
                    continue;
                }
                ExaminationPaper paper = new ExaminationPaper();
                paper.setModifier(account);
                paper.setAccount(x.getAccount());
                int count = examinationPaperService.getBaseMapper().update(paper, Wrappers.<ExaminationPaper>lambdaQuery().eq(ExaminationPaper::getEnable, 1)
                        .in(ExaminationPaper::getAdmissionTicketCode, admissionTicketCodes)
                        .eq(ExaminationPaper::getCourse, bo.getCourse())
                        .isNull(ExaminationPaper::getAccount).last("LIMIT " + x.getCount()));
                if (count > 0) {
                    doSaveTeacherAllocation(x, count);
                }
            }

        }
        //按考场分配
        if (distributeTypeEnum == DistributeTypeEnum.EXAMINATION) {
            if (countVO > examinationCount()) {
                throw new ArtException(5004, "考场总数配置超过总数");
            }
            for (DistributeBO.TeacherAllocationBO x : bo.getTeachers()) {
                List<ExaminationInfo> examinationInfos = getExaminationInfos(bo, x.getProvinces(), x.getCount());
                if (CollectionUtils.isEmpty(examinationInfos)) {
                    log.warn("未找到对应的考场");
                    continue;
                }
                List<ExaminationInfo> newInfo = examinationInfos.stream().map(z -> {
                    ExaminationInfo info = new ExaminationInfo();
                    info.setAccount(x.getAccount());
                    info.setId(z.getId());
                    ExaminationPaper model = new ExaminationPaper();
                    model.setAccount(x.getAccount());
                    model.setModifier(account);
                    int count = examinationPaperService.getBaseMapper().update(model, Wrappers.<ExaminationPaper>lambdaQuery()
                            .eq(ExaminationPaper::getEnable, 1).eq(ExaminationPaper::getExamCode, z.getExamCode()));
                    if (count > 0) {
                        doSaveTeacherAllocation(x, count);
                    }
                    return info;
                }).collect(Collectors.toList());
                examinationInfoService.updateBatchById(newInfo, newInfo.size());
            }
            Constants constants1 = new Constants();
            constants1.setLockKey(Constant.DISTRIBUTE_TYPE);
            constants1.setLockValue(bo.getDistributeType());
            constantsService.save(constants1);
        }
        return false;
    }

    private List<ExaminationInfo> getExaminationInfos(DistributeBO bo, List<String> provinces, Integer count) {
        LambdaQueryWrapper<ExaminationInfo> wrapper = Wrappers.<ExaminationInfo>lambdaQuery().eq(ExaminationInfo::getActivityStatus, 1)
                .eq(ExaminationInfo::getProvince, provinces).select(ExaminationInfo::getId, ExaminationInfo::getExamCode)
                .isNull(ExaminationInfo::getAccount).last("LIMIT " + count);
        if (StringUtils.equals(bo.getCourse(), CourseEnum.COLOR.getName())) {
            wrapper.eq(ExaminationInfo::getIsColor, 1);
        } else if (StringUtils.equals(bo.getCourse(), CourseEnum.SKETCH.getName())) {
            wrapper.eq(ExaminationInfo::getIsSketch, 1);
        } else if (StringUtils.equals(bo.getCourse(), CourseEnum.WRITING.getName())) {
            wrapper.eq(ExaminationInfo::getIsWriting, 1);
        } else if (StringUtils.equals(bo.getCourse(), CourseEnum.COMPOSE.getName())) {
            wrapper.eq(ExaminationInfo::getIsCompose, 1);
        } else {
            throw new ArtException(5101, "科目类型没找到");
        }
        return examinationInfoService.list(wrapper);
    }

    private void doSaveTeacherAllocation(DistributeBO.TeacherAllocationBO x, int count) {
        TeacherAllocation model = new TeacherAllocation();
        model.setAccount(x.getAccount());
        model.setName(x.getName());
        model.setCount(count);
        teacherAllocationService.save(model);
        allocationProvinceService.saveBatch(x.getProvinces().stream().map(y -> {
            AllocationProvince allocationProvince = new AllocationProvince();
            allocationProvince.setAllocationId(model.getId());
            allocationProvince.setProvince(y);
            return allocationProvince;
        }).collect(Collectors.toList()));
    }
}
